package com.larsgard.gedviewer.server.storage;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.logging.Logger;

import com.larsgard.gedviewer.server.storage.entities.JDOPerson;
import com.larsgard.gedviewer.server.storage.entities.JDOUserTree;
import com.larsgard.gedviewer.shared.PersonDetails;
import com.larsgard.gedviewer.shared.ajax.SearchRequest;

public class PersonStorage extends Storage<JDOPerson> {

    private static final Logger log = Logger.getLogger(PersonStorage.class.getName());

    private static PersonStorage INSTANCE;

    private PersonStorage() {

    }

    public static PersonStorage getInstance() {
	if (INSTANCE == null) {
	    INSTANCE = new PersonStorage();
	}
	return INSTANCE;
    }

    public JDOPerson persistPerson(JDOPerson person) {
	if (person.getKey() == null) {
	    person.setKey(createKey(person, person.getIdno(), null));
	}
	return super.storeObject(person);
    }

    public JDOPerson getPerson(String idno) {
	String filter = "idno == '" + idno + "'";
	ArrayList<JDOPerson> result = super.getObjectList(JDOPerson.class, 0, 1, null, filter);
	JDOPerson person = null;
	if (result.size() == 1) {
	    person = result.get(0);
	}
	return person;

    }

    public ArrayList<JDOPerson> getAllPersons(String password) {
	String filter = "treeId == '" + getTreeIdForPassword(password) + "'";
	ArrayList<JDOPerson> result = super.getObjectList(JDOPerson.class, 0, 60, null, filter);
	return result;
	// return super.getObjectList(Person.class, 0, 60, null, null);
    }

    public PersonDetails[] getPersonDetails(String[] idno, int depth) {
	PersonDetails[] result = new PersonDetails[idno.length];
	for (int i = 0; i < result.length; i++) {
	    result[i] = getPersonDetails(idno[i], 0, depth);
	}
	return result;
    }

    private PersonDetails getPersonDetails(String idno, int depth, int maxDepth) {

	PersonDetails result = new PersonDetails();
	if (idno == null) {
	    return result;
	}
	result.setDepth(depth);
	result.setMaxDepth(maxDepth);
	JDOPerson mainPerson = getPerson(idno);
	if (mainPerson == null) {
	    log.warning("Got a null-response from jdo for person with idno" + idno);
	    return result;
	}
	result.setMainPerson(mainPerson.getPerson());
	if (depth == maxDepth) {
	    return result;
	}
	PersonDetails[] parents = new PersonDetails[2];
	if (mainPerson.getFatherIdno() != null) {
	    parents[0] = getPersonDetails(extractIdno(mainPerson.getFatherIdno()), depth + 1,
		    maxDepth);
	}
	if (mainPerson.getMotherIdno() != null) {
	    parents[1] = getPersonDetails(extractIdno(mainPerson.getMotherIdno()), depth + 1,
		    maxDepth);
	}
	result.setParents(parents);

	return result;
    }

    private String extractIdno(String fatherIdno) {
	if (fatherIdno.contains("-")) {
	    fatherIdno = fatherIdno.substring(0, fatherIdno.indexOf('-'));
	}
	return fatherIdno;
    }

    public ArrayList<JDOPerson> getPersons(SearchRequest request) {
	String treeId = getTreeIdForPassword(request.getPassword());
	if (treeId == null) {
	    return new ArrayList<JDOPerson>();
	}

	String filter = null;
	int criteriaCount = 0;
	if (!isBlank(request.getFirstName())) {
	    filter = "givenName.startsWith(\"" + request.getFirstName() + "\")";
	    criteriaCount++;
	}
	if (!isBlank(request.getFamilyName())) {
	    if (isBlank(filter)) {
		filter = "familyName.startsWith(\"" + request.getFamilyName() + "\")";
	    }
	    criteriaCount++;
	}
	if (!isBlank(request.getSex())) {
	    if (isBlank(filter)) {
		filter = "sex.startsWith(\"" + request.getSex() + "\")";
	    }
	    criteriaCount++;
	}

	filter += " && treeId =='" + treeId + "'";

	if (criteriaCount == 0) {
	    return getAllPersons(request.getPassword());
	} else {
	    ArrayList<JDOPerson> result = super
		    .getObjectList(JDOPerson.class, 0, 140, null, filter);
	    if (criteriaCount > 1) {
		Iterator<JDOPerson> iterator = result.iterator();
		while (iterator.hasNext()) {
		    JDOPerson next = iterator.next();
		    if (!isBlank(request.getFamilyName())) {
			if (!next.getFamilyName().startsWith(request.getFamilyName())) {
			    iterator.remove();
			    continue;
			}
		    }
		    if (!isBlank(request.getSex())) {
			if (!next.getSex().startsWith(request.getSex())) {
			    iterator.remove();
			    continue;
			}
		    }

		}
	    }
	    return result;
	}
    }

    private String getTreeIdForPassword(String password) {
	JDOUserTree treeWithPassword = TreeStorage.getInstance().getTreeWithPassword(password);
	if (treeWithPassword == null) {
	    return null;
	}
	return treeWithPassword.getTreeId();
    }

    private boolean isBlank(String string) {
	return string == null || string.trim().equals("");
    }

    public void persistAll(ArrayList<JDOPerson> persons) {
	super.storeObjects(persons);
    }

    public void deleteAllWithTreeId(String treeId) {
	String filter = " treeId == '" + treeId + "'";
	ArrayList<JDOPerson> personsToDelete = super.getObjectList(JDOPerson.class, 0, 100000,
		null, filter);
	for (JDOPerson jdoPerson : personsToDelete) {
	    super.deleteObject(jdoPerson);
	}

    }

}
